package vision;

import game.Constants;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

public class Vision implements Runnable {

	// Server socket
	private ServerSocket server;
	
	// Network port to listen on
	private int port;
	
	// Determine whether the Vision server is running.
	private volatile boolean running = false;
	
	// Determine whether CV is calibrated.
	private volatile boolean calibrated = false;
	
	private OutputStream outClient;
	private BufferedReader inFromClient;
	private ObjectFinder objectfinder;
	private Socket connected = null;

	/**
	 * Class constructor.
	 */
	public Vision() {
		this.port = Constants.visionPort;
		objectfinder = new ObjectFinder();
	}

	public void start() throws IOException {
		server = new ServerSocket(port);
		running = true;
		System.out.println("Serversocket open");
		Thread t = new Thread(this, "server");
		t.start();
	}

	@Override
	public void run() {
		while (running) {
			try {
				connected = server.accept();
				System.out.println("Wait for client...");
				System.out.println("Client connected");

				outClient = connected.getOutputStream();
				inFromClient = new BufferedReader(new InputStreamReader(
						connected.getInputStream()));

				sendResolution();
				//calibrate();
				

				while (!connected.isClosed()) {
					String data = inFromClient.readLine();
					if (data != null) {
						if (data.equals("Quit") || data.equalsIgnoreCase("")) {
							connected.close();
							running = false;

						} else if (data.equalsIgnoreCase("Calibrated")) {
							calibrated = true;
						} else {
							data = "{\"Coordinates\":" + data + "}";
							try {
								JSONObject input = new JSONObject(data);
								JSONArray coordinates = input.getJSONArray("Coordinates");
								if (input != null) {
									System.out.println("bier");
									objectfinder.fill_field(coordinates);
								}
							} catch (JSONException e) {
								e.printStackTrace();
							}
						}
					} else {
						connected.close();
					}
				}
			} catch (IOException e) {
				System.out.println("Connection lost, connection closed");
			}
		}
	}

	/**
	 * Get the map.
	 * @return The map.
	 */
	public int[][] getMap() {
		return objectfinder.field;
	}

	/**
	 * Send the resolution.
	 * @throws IOException	When writing to OS fails.
	 */
	public void sendResolution() throws IOException {
		if (!connected.isClosed()) {
			outClient.write(("screen " + objectfinder.getResolution())
					.getBytes());
		}
	}

	/**
	 * Send message to calibrate.
	 * @throws IOException	When writing to OS didn't work.
	 */
	public void calibrate() throws IOException {
		calibrated = false;
		if (!connected.isClosed()) {
			outClient.write("calibrate".getBytes());
		}
	}
	
	/**
	 * Check if the CV is calibrated.
	 * @return Calibrated or not.
	 */
	public boolean isCalibrated(){
		return calibrated;
	}
}
